#ifndef LB_Sparse_Matrix_H_
#define LB_Sparse_Matrix_H_
#define Sparse_Matrix LB_Sparse_Matrix 
#include<Math/LB_Math.h>

#ifdef __cplusplus
extern "C" {
#endif

// typedef struct LB_Sparse_Matrixn{
//     int rows,cols;
//     int*i_index;
//     int n;
//     double**data;
// }LB_Sparse_Matrixn;
// static inline void lb_sparse_matrixn_init(LB_Sparse_Matrixn*lsm)
// {
//     lsm->i_index=NULL;
//     lsm->data=NULL;
//     lsm->rows=0;lsm->cols=0;lsm->n=0;
// }
// static inline void lb_sparse_matrixn_reserve(LB_Sparse_Matrixn*lsm,int n)
// {
//     lsm->i_index=(int*)malloc(sizeof(int)*n);
//     memset(lsm->i_index,0,sizeof(int)*n);

//     lsm->n=n;
//     lsm->data=(double**)malloc(sizeof(double*)*lsm->rows);
//     for(int i=0;i<n;i++)
//     {
//         lsm->data[i]=(double*)malloc(sizeof(double)*n);
//         memset(lsm->data[i],0,sizeof(double)*n);
//     } 
// }













typedef struct LB_Sparse_Matrix_Node{
    int i,j;
    double data;
    struct LB_Sparse_Matrix_Node* right,*down;
}LB_Sparse_Matrix_Node;
static inline void lb_sparse_matrix_node_init(LB_Sparse_Matrix_Node* lsmn )
{   
    lsmn->i=0;lsmn->j=0;lsmn->data=0;
    lsmn->right=NULL;lsmn->down=NULL;
}
static inline void lb_sparse_matrix_node_free(LB_Sparse_Matrix_Node* lsmn )
{   
    SAFE_FREE(lsmn);
}
typedef struct LB_Sparse_Matrix{
    LB_Sparse_Matrix_Node** rhead,**chead;
    int rows,cols,n_nz;
    void *prop;
}LB_Sparse_Matrix;

static inline void lb_sparse_matrix_init(LB_Sparse_Matrix*lsm)
{
    lsm->rhead=NULL;lsm->chead=NULL;
    lsm->rows=0;lsm->cols=0;lsm->n_nz=0;
    lsm->prop=NULL;
}
void lb_sparse_matrix_free(LB_Sparse_Matrix*lsm);



static inline void lb_sparse_matrix_initn(LB_Sparse_Matrix*lsm,int rows,int cols ,int n_nz)
{
    lsm->rows=rows;lsm->cols=cols;lsm->n_nz=n_nz;
    lsm->prop=NULL;
    lsm->rhead=(LB_Sparse_Matrix_Node**)malloc(sizeof(LB_Sparse_Matrix_Node*)*(lsm->rows+1));
    lsm->chead=(LB_Sparse_Matrix_Node**)malloc(sizeof(LB_Sparse_Matrix_Node*)*(lsm->cols+1));
    
    memset(lsm->rhead,0,sizeof(LB_Sparse_Matrix_Node*)*(lsm->rows+1));
    memset(lsm->chead,0,sizeof(LB_Sparse_Matrix_Node*)*(lsm->cols+1));
}

void lb_sparse_matrix_insert(LB_Sparse_Matrix*lsm,int i,int j,double data);




static inline double lb_sparse_matrix_get_data(LB_Sparse_Matrix*lsm,int i,int j)
{
    LB_Sparse_Matrix_Node*q=NULL; 
    for(q=lsm->rhead[i];q!=NULL&&q->j<j;q=q->right);
    if(q==NULL)
    {
        return 0;
    }
    return q->data;
}

static inline LB_Sparse_Matrix* lb_sparse_matrix_mult_sparse_matrix(LB_Sparse_Matrix*lsm1,LB_Sparse_Matrix*lsm2)
{
    LB_Sparse_Matrix* re=(LB_Sparse_Matrix*)malloc(sizeof(LB_Sparse_Matrix));
    lb_sparse_matrix_init(re);
    LB_Sparse_Matrix_Node*q=NULL,*p=NULL;  
    for(int i=0;i<lsm1->rows;i++)
    {
        for(int j=0;j<lsm2->cols;j++)
        {
            double temp=0;
            p=lsm2->chead[j];
            for(q=lsm1->rhead[i];q!=NULL;q=q->right)
            {

                for(;p!=NULL&&p->i<q->j;p=p->down);
                if(p->i==q->j)
                {
                    temp+=p->data*q->data;
                }  
            }
            if(temp!=0)
            {
                lb_sparse_matrix_insert(re,i,j,temp);
            }
        }
    }
    return re;
}

static inline double* lb_sparse_matrix_mult_array(LB_Sparse_Matrix* lsm,double* vec)
{
    double *re=(double*)malloc(sizeof(double)*lsm->rows);
    memset(re,0,sizeof(double)*lsm->rows);
    LB_Sparse_Matrix_Node*q=NULL;
    for(int i=0;i<lsm->rows;i++)
    {
        for(q=lsm->rhead[i];q!=NULL;q=q->right)
        {
            re[i]+=q->data*vec[q->j];
        }
    }
    return re;
}


double* compute_conjugate_gradient(LB_Sparse_Matrix*lsm,double* b);



#ifdef __cplusplus
}
#endif

#undef Sparse_Matrix
#endif